package com.mszlu.rpc.proxy;

//import com.mszlu.rpc.annontation.MsMapping;
import com.mszlu.rpc.annotation.MsReference;
import com.mszlu.rpc.exception.MsRpcException;
import com.mszlu.rpc.message.MsRequest;
import com.mszlu.rpc.message.MsResponse;
import com.mszlu.rpc.netty.NettyClient;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

//每一个动态代理类的调用处理程序都必须实现InvocationHandler接口，
// 并且每个代理类的实例都关联到了实现该接口的动态代理类调用处理程序中，
// 当我们通过动态代理对象调用一个方法时候，
// 这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用
@Slf4j
public class MsRpcClientProxy implements InvocationHandler {


    public MsRpcClientProxy(){

    }
     private MsReference msReference;
    private NettyClient nettyClient;

    public MsRpcClientProxy(MsReference msReference, NettyClient nettyClient) {
        this.msReference = msReference;
        this.nettyClient = nettyClient;
    }

    /**
     * proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0
     * method:我们所要调用某个对象真实的方法的Method对象
     * args:指代代理对象方法传递的参数
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //在这里实现调用
//        System.out.println("rpc的代理实现类 调用了...");
            //构建请求数据
        log.info("proxy call");
            String requestId = UUID.randomUUID().toString();
            MsRequest request = MsRequest.builder()
                    .methodName(method.getName())
                    .parameters(args)
                    .interfaceName(method.getDeclaringClass().getName())
                    .paramTypes(method.getParameterTypes())
                    .requestId(requestId)
                    .version(msReference.version())
                    .build();
            //创建Netty客户端
            String host = msReference.host();
            int port = msReference.port();
            CompletableFuture<MsResponse<Object>> future = (CompletableFuture<MsResponse<Object>>) nettyClient.sendRequest(request, host, port);
            MsResponse<Object> msResponse = future.get();
            if (msResponse == null){
                throw new MsRpcException("服务调用失败");
            }
            if (!requestId.equals(msResponse.getRequestId())){
                throw new MsRpcException("响应结果和请求不一致");
            }
            return msResponse.getData();




//        //在这里实现调用
//        System.out.println("rpc的代理实现类 调用了...");
//        MsRequest request = MsRequest.builder()
//                .methodName(method.getName())
//                .parameters(args)
//                .interfaceName(method.getDeclaringClass().getName())
//                .paramTypes(method.getParameterTypes())
//                .requestId(UUID.randomUUID().toString())
//                .version(msReference.version())
//                .build();
//        //创建Netty客户端
//        String host = msReference.host();
//        int port = msReference.port();
//
//        return null;
    }

    /**
     * get the proxy object
     */
    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<T> clazz) {
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[]{clazz}, this);
    }

}
